/*
* 2010
* Authors: Dmitry Kolyanov <dk90.spb@gmail.com>, Ksenyia Cypan <ksenyiacypan@gmail.com>
*
* hierarchial social metaheuristics for the maxcut 
* combinatorial design approach to maxcut
*/
#include "stdafx.h"

#define BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS

#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/random.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real.hpp>

using namespace boost;

const char* INGRAPH = "Ingraph.dot";
const char* OUTGRAPH = "Outgraph.dot";
const char* RNDGRAPH = "random.dot";
const int ERROR = -1;

int graph_read(Graph& g)
{
	std::string input;
	dynamic_properties dp;

	std::cin >> input;
	std::ifstream ifile(input.c_str());

	if(!ifile)
	{
		std::cerr << "Error: cannot open the file. \n";
		ifile.close();
		return ERROR;
	}

	property_map<Graph, boost::vertex_name_t>::type name =
		get(vertex_name, g);
	dp.property("node_id",name);

	property_map<Graph, boost::vertex_color_t>::type mass =
		get(vertex_color, g);
	dp.property("label",mass);

	property_map<Graph, boost::edge_weight_t>::type weight =
		get(edge_weight, g);
	dp.property("label",weight);

	try
	{
		read_graphviz(ifile, g, dp, "node_id");
	}
	catch(bad_parallel_edge)
	{ 
		std::cout<<"Please, remove parallel edges\n";
		return ERROR;
	}
	catch(undirected_graph_error)
	{ 
		std::cout<<"Tried to read an undirected graph into a directed graph.";
		return ERROR;
	}
	catch(directed_graph_error)
	{ 
		std::cout<<"Tried to read a directed graph into an undirected graph.\n";
		return ERROR;
	}
	ifile.close();
	return 0;
}

void graph_write(Graph& g, const char* name)
{
	std::ofstream file(name);             
	property_map<Graph, vertex_color_t>::type mass = get(vertex_color, g);
	property_map<Graph, edge_weight_t>::type weight = get(edge_weight, g);
	write_graphviz(file, g, make_label_writer(mass), make_label_writer(weight));
	file.close();
}

void create_random_graph(Graph &rnd_graph, size_t nV, size_t nE)
{
	rnd_graph.clear();
	boost::uniform_real<> ur(1,20);
	mt19937 rng;
	rng.seed(uint32_t(time(0)));
	generate_random_graph(rnd_graph, nV, nE, rng, false, false);
	boost::variate_generator<boost::mt19937&, boost::uniform_real<> >   ew1rg(rng, ur);
	randomize_property<edge_weight_t>(rnd_graph, ew1rg);
}

int main()
{
	clock_t start, end;
	Graph testGraph, rnd_graph;
	char input;

	std::cout << "Enter dot file name with graph: \n";
	if(graph_read(testGraph) == ERROR) 
		return ERROR;
	graph_write(testGraph, INGRAPH);

	std::cout << "Enter alghoritm to use c/g: ";
	std::cin >> input;
	std::cout << "\n";

/*
	rnd_graph = Graph(0);
	create_random_graph(rnd_graph, 50, 500);
	graph_write(rnd_graph, RNDGRAPH);
	rnd_graph.clear();
	std::cout << "Written";*/

	maxcut m;

	switch(input)
	{
	case 'c':
		std::cout << "Combinatorial algorithm: \n";
		start = clock();
		m.combinatorial_algorithm(testGraph);
		end = clock();
		break;
	case 'g':
		std::cout << "Genetic algorithm: \n";
		start = clock();
		m.genetic_algorithm(testGraph);
		end = clock();
		break;
	default:
		std::cout << "wrong algorithm \n";
		return 0;
	}

	printf ("maxcut size is %2.2f.\n", m.get_maxcut_size());
	printf ("Running time is %2.2f seconds.\n", (double)(end - start) / CLOCKS_PER_SEC);
	std::cout << "\n";
	//write given graph to the dot file
	graph_write(testGraph, OUTGRAPH);
	std::cout << "Written\n";

	return 0;
}